<?php

namespace App\Controller\Api\V1;


use App\Common\Helper;
use App\Constants\CacheKey;
use App\Job\ChatJob;
use App\Services\UserAuth;
use App\Services\WsService;
use Hyperf\Redis\Redis;
use Hyperf\Utils\Codec\Json;
use Hyperf\WebSocketServer\Context;
use Swoole\Http\Request;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnOpenInterface;
use Hyperf\Contract\OnMessageInterface;
use Swoole\WebSocket\Frame;
use Hyperf\HttpServer\Request as HttpRequest;
use Hyperf\HttpServer\Response as HttpResponse;
use Psr\Http\Message\ResponseInterface;
use Hyperf\Di\Annotation\Inject;

/**
 * 目前仅支持活动会议群聊
 * Class WebSocketController
 * @package App\Controller\Api\V1
 */
class WebSocketController implements OnCloseInterface,OnOpenInterface,OnMessageInterface
{
    /**
     * @Inject
     * @var WsService
     */
    protected $wsService;

    public function onRequest(HttpRequest $request, HttpResponse $response): ResponseInterface
    {
       $token = $request->header(UserAuth::X_TOKEN) ?? '';
       $data = $request->post('data');
       $result = $this->wsService->calls($data, $token);
       return $response->json($result);
    }

    public function onMessage($server, Frame $frame): void
    {
        if ($frame->data === 'heartCheck') {
            //心跳检测
            $server->push($frame->fd, 'pong');
        } else {
            $mid = Context::get("meetingId");
            var_dump([
                "action" => "onMessage",
                "meetingId" => $mid,
                "data" => $frame->data
            ]);
            if (!empty($mid)) {
                $fd = $frame->fd;
                $redis = di()->get(Redis::class);
                $key = sprintf(CacheKey::MEETING_GROUP_CHAT_KEY,  $mid);
                $fd_key = sprintf(CacheKey::MEETING_GROUP_CHAT_FD_KEY, $mid);
                $nickname = $redis->hGet($fd_key, (string)$fd);
                $cache = $redis->sMembers($key);
                $data = Json::decode($frame->data);
                $data['nickname'] = $nickname;
                $data['meetingId'] = $mid;
                queue_push(new ChatJob($data));
                foreach ($cache as $sfd) {
                    $server->push($sfd, Json::encode($data));
                }
            } else {
                $server->push($frame->fd, "活动会议不存在");
            }
        }
    }

    public function onOpen($server, Request $request): void
    {
        $mid = $request->get['meetingId'];
        $token = $request->get['token'] ?? '';
        if (empty($mid) || !($this->wsService->checkMeeting($mid))) {
            echo "活动/会议：$mid 不存在或已结束" . PHP_EOL;
            $server->push($request->fd, '活动不存在或已结束');
            $server->close($request->fd);
        } else {
            Context::set("meetingId", $mid);
            var_dump([
                "action" => "onOpen",
                "fd" => $request->fd,
                'meetingId' => $mid
            ]);
            $redis = di()->get(Redis::class);
            //判断用户是否已登录
            $key = CacheKey::USER_AUTH_KEY . $token;
            if ($redis->exists($key)) {
                $user = Json::decode($redis->get($key));
                $nickname = $user['nickname'];
            } else {
                $nickname = Helper::instance()->rndChinaName();
            }
            $fd = $request->fd;
            $server->push($fd, Json::encode(["pushType"=>"name", "nickname"=>$nickname]));
            //缓存websocket连接成功用户数据
            $chat_key = sprintf(CacheKey::MEETING_GROUP_CHAT_KEY, $mid);
            $fd_key = sprintf(CacheKey::MEETING_GROUP_CHAT_FD_KEY, $mid);
            $redis->sAdd($chat_key, $fd);
            $redis->hSet($fd_key, (string)$fd, $nickname);
            $cache = $redis->sMembers($chat_key);
            $data = [
                "pushType" => "msg",
                "meetingId" => $mid,
                "msgType" => 0,
                "senderId" => 0,
                "senderType" => 2,
                "senderName" => "系统",
                "content" => $nickname.'进入群聊',
                "sendTime" => date('Y-m-d H:i:s'),
            ];
//            queue_push(new ChatJob($data));
            foreach ($cache as $sfd) {
                $server->push($sfd, Json::encode($data));
            }
        }
    }

    /**
     * @inheritDoc
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $redis = di()->get(Redis::class);
        $mid = Context::get('meetingId');
        $key = sprintf(CacheKey::MEETING_GROUP_CHAT_KEY,  $mid);
        $fd_key = sprintf(CacheKey::MEETING_GROUP_CHAT_FD_KEY, $mid);
        $nickname = $redis->hGet($fd_key, (string)$fd);
        var_dump([
            "msg" => "退出群聊",
            "mid" => $mid,
            "nickname" => $nickname
        ]);
        //移除退出用户缓存数据
        $redis->hDel($fd_key, (string)$fd);
        $redis->sRem($key, $fd);
        //缓存无数据则删除key
        if ($redis->hLen($fd_key) == 0) {
            $redis->del($fd_key);
        }
        if ($redis->sCard($key) == 0) {
            $redis->del($key);
        } else {
            $cache = $redis->sMembers($key);
            foreach ($cache as $ch) {
                $server->push($ch, $nickname.'退出群聊');
            }
        }
    }

}
